#ifndef __CE_SCENE_RENDERBUCKET_H__
#define __CE_SCENE_RENDERBUCKET_H__

#include <export.h>
#include <vector>
#include <list>
#include <map>


struct ceMatrix4f;
struct iDevice;
struct ceMaterialSpec;
class ceSharedShaderBinding;
struct iMesh;
class ceEntityNode;
class ceLightObject;
class ceGeometry;
struct iEffectCamera;
struct iEffectTechnique;
class ceTexturePack;
struct ceRenderEnvironment;

/**
 * \addtogroup scene
 * @{
 */

/**
 * @brief Bucket filled with renderable object for performing the rendering
 */
class CE_API ceRenderBucket
{
private:
  struct SpatialGeometry
  {
    ceMaterialSpec& _material;
		ceSharedShaderBinding& _sharedBindings;
    const ceMatrix4f& _matrix;
    iMesh* _mesh;
    ceEntityNode* _node;
    SpatialGeometry (ceMaterialSpec& material, ceSharedShaderBinding& sharedBindings, const ceMatrix4f& matrix, iMesh* mesh, ceEntityNode* node)
      : _material (material)
			, _sharedBindings (sharedBindings)
      , _matrix (matrix)
      , _mesh (mesh)
      , _node (node)
    {

    }
  };
  typedef std::list<SpatialGeometry> SpatialGeometryList;
  typedef std::map<ceTexturePack*, SpatialGeometryList> TextureGeometryList;
  typedef std::map<iEffectTechnique*, TextureGeometryList> EffectTextureGeometryList;
  typedef std::vector<ceLightObject*> LightVector;

  EffectTextureGeometryList _renderElements;
  EffectTextureGeometryList _transparentRenderElements;
  EffectTextureGeometryList _unlitRenderElements;

  LightVector                 _lights;

  std::vector<iEffectCamera*> _effectCameras;

  bool  _visited;
  std::list<ceRenderBucket*>  _next;
  unsigned _num, _numSolid, _numTransparent, _numUnlit;
private:
  void Render(EffectTextureGeometryList& list,  const ceRenderEnvironment &env, iDevice *device, ceRenderPass pass, bool renderAll);
public:
  ceRenderBucket ();
  void Clear ();

  void Add (iEffectTechnique* effect, ceTexturePack* tp, ceMaterialSpec& material, ceSharedShaderBinding& sharedBinding, const ceMatrix4f& matrix,
            iMesh* mesh, ceEntityNode* node);
  void Add (ceLightObject* light);
  void Add (iEffectCamera* camera);

  void Render (const ceRenderEnvironment& env, iDevice* device, ceRenderPass pass, bool renderAll);
  void RenderSolid (const ceRenderEnvironment& env, iDevice* device, ceRenderPass pass, bool renderAll);
  void RenderTransparent (const ceRenderEnvironment& env, iDevice* device, ceRenderPass pass, bool renderAll);
  void RenderUnlit(const ceRenderEnvironment& env, iDevice* device, ceRenderPass pass, bool renderAll);
  void RenderBoundingBoxes (const ceRenderEnvironment& env, iDevice* device);

  void BindLights (iDevice* light, ceEntityNode* entity);
  unsigned GetNumberOfLights () const;
  ceLightObject* GetLight (unsigned light);
  ceLightObject* BindLight (iDevice* device, unsigned light);

  unsigned GetNumberOfEffectCameras () const;
  iEffectCamera* GetEffectCamera (unsigned idx);

  void AddNext (ceRenderBucket* bucket);
  void SetVisited (bool visited);
  unsigned GetNumberOfElements ();

  void Debug ();
};


/** @} */
#endif /* ! __CE_SCENE_RENDERBUCKET_H__ */
